package gui.batches;

import gui.common.DataConverter;
import gui.inventory.ProductContainerData;
import gui.product.ProductData;
import hitExceptions.InvalidOperationException;

import java.util.ArrayList;
import java.util.Timer;
import java.util.TreeSet;

import coreModel.Barcode;
import coreModel.HIT;
import coreModel.Item;
import coreModel.Product;
import coreModel.ProductContainer;

/**
 * Controller class for the transfer item batch view.
 */
public class TransferItemBatchController extends ItemBatchController implements
		ITransferItemBatchController
{
	
	/**
	 * Constructor.
	 * 
	 * @param view Reference to the transfer item batch view.
	 * @param target Reference to the storage unit to which items are being transferred.
	 */
	public TransferItemBatchController(ItemBatchView view, ProductContainerData target) 
	{
		super(view, target);
		
		construct();
	}
	
	/**
	 * Returns a reference to the view for this controller.
	 */
	@Override
	protected TransferItemBatchView getView() 
	{
		return (TransferItemBatchView)super.getView();
	}

	/**
	 * This method is called when the "Item Barcode" field in the
	 * transfer item batch view is changed by the user.
	 */
	@Override
	public void barcodeChanged() 
	{//added to automatically getting the barcode
		if(useScanner && notScheduled)
		{
			notScheduled=false;
			BarcodeReaderForTransferring br= new BarcodeReaderForTransferring();
			try
			{
				timer.schedule(br, BARCODE_TIME);
			}
			catch (IllegalStateException e) //should reach here iff timer was canceled
			{
				timer = new Timer("barCode thread");
				timer.schedule(br, BARCODE_TIME);
			}
		}
		else if(!useScanner)
		{
			enableComponents();
			timer.cancel();
		}
	}

	
	/**
	 * This method is called when the user clicks the "Transfer Item" button
	 * in the transfer item batch view. It will find the item identified 
	 * by the barcode entered into the view. Then it will transfer it into 
	 * the target container. (See the specifications for details on this transfer.)
	 */
	@Override
	public void transferItem() 
	{
		
		Product addedProduct = null;
		
		//find the item by its barcode
		Barcode iBarcode = new Barcode(getView().getBarcode());
		Item i = itemManager.getItem(iBarcode);
		
		//check to see if the item exists
		if (i == null)
		{
			getView().displayErrorMessage("The specified item does not exist.");
			getView().setBarcode("");
			return;
		}
		
		//check to see if the item is already in target
		if(i.getParentContainer().equals(target))
		{
				getView().displayErrorMessage("The specified item is already there.");
				getView().setBarcode("");
				return;
		}
		
		ArrayList<Item> itemList = new ArrayList<Item>();
		
		itemList.add(i);
		
		//get the item's container
		ProductContainer oldParent = i.getParentContainer();
		
		//find the Product Container in target that contains the item's product
		Product p = i.getProduct();
		ProductContainer newParent = productManager.locationOfProductInContainer(p, target);
		
		redoStack.clear();
		
		boolean firstTime;
		
		
		if(newParent == null)
			firstTime = true;
		else
			firstTime = false;
		
		System.out.println(firstTime);
		
		Transfer items = new Transfer(itemList, oldParent, newParent,firstTime);
		items.redo();
		
		undoStack.push(items);
		
		getView().giveBarcodeFocus();
		getView().setBarcode("");
		loadValues();
		
		enableComponents();
		
			
		
	}

	
	/**
	 * This method is called when the user clicks the "Redo" button
	 * in the add item batch view.
	 */
	@Override
	public void redo() 
	{
		
		redoStack.peek().redo();
		undoStack.push(redoStack.pop());
		loadValues();
		enableComponents();
			
	}

	/**
	 * This method is called when the user clicks the "Undo" button
	 * in the add item batch view.
	 */
	@Override
	public void undo() 
	{	
		
		undoStack.peek().undo();
		redoStack.push(undoStack.pop());
		loadValues();
		enableComponents();

	}
	
	
	/**
	 * Private class for keeping track of transfers we might undo/redo
	 * in the transfer item batch view.
	 */
	private class Transfer extends Command
	{

		ProductContainer from;
		ProductContainer to;
		boolean firstTime;
				
				
		/** Constructor
		 * 
		 * @param item The item to be transferred.
		 */
		public Transfer(ArrayList<Item> i, ProductContainer f, ProductContainer t, boolean first){
			items = i;
			from = f;
			
			to=t;
			firstTime = first;
			
			
		}
		


		
		public ArrayList<Item> getItems(){
			return items;
		}
		
				
		
		
		
		public void redo()
		{												
				//itemFacade.addItems(items);
				//productFacade.addProduct(items.get(0).getProduct(), target);
				
				
			//if there exists a container in target that has the item's product
			if (to != null)
			{
				
				//move the item to that container
				try 
				{
					itemFacade.transferItem(items.get(0), to);
				} 
				catch (InvalidOperationException e) 
				{
					
					System.err.println("Error1 in TransferItemBatchController::transferItem(): "
							+ "\n\t" + e);
					return;
				}
			}
			else
			{
								
				productFacade.addProduct(items.get(0).getProduct(), target);
				
				
				try 
				{
					
					HIT.getInstance().getItemManager().addContainer(target);
				
					
					itemFacade.transferItem(items.get(0), target);
				} 
				catch (InvalidOperationException e) 
				{
					
					System.err.println("Error3 in TransferItemBatchController::transferItem(): "
							+ "\n\t" + e);
					return;
				}
				
				to = target;
			}
			
			
				
		}
		
		
		/**
		 * Undoes (makes undone) this addition, and all of its effects. This includes 
		 * all additions contained within (if this is compound) and also includes 
		 * any product creation.
		 */
		@Override
		public void undo()
		{
		
			
			try 
			{
				itemFacade.transferItem(items.get(0), from);
			} 
			catch (InvalidOperationException e) 
			{
				System.err.println("Error3 in TransferItemBatchController::transferItem(): "
						+ "\n\t" + e);
				return;
			}
			
			if(firstTime == true){	
				try{
					productFacade.removeProductFromContainer(items.get(0).getProduct(), target);
					
				}
				catch(Exception e){
					System.out.println("got here");
					
				}
				}
			
		}

		
		
	}

	/** Private class for the barcode scanning timer in the transfer item batch view. 
	 * 
	 */
	private class BarcodeReaderForTransferring extends BarcodeReader
	{
		/** 
		 * This will be called when this timer runs out. 
		 */
		@Override
		public void run()
		{
			if(getView().getBarcode().length()>0) // change to check to enabled support
				transferItem();
			
			notScheduled=true;
			getView().setBarcode("");
		}
	}
	
}

